#pragma once

#define DISABLE_PCAP_PARSE
#include <iomanip>
#include <iostream>
#include <limits>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include <map>

#include "cyber/cyber.h"
#include "modules/common_msgs/sensor_msgs/pointcloud.pb.h"
#include "modules/drivers/lidar/common/driver_factory/driver_base.h"
#include "modules/drivers/lidar/livox/proto/livox_config.pb.h"
#include "data_type.h"
#include "data_buffer.h"
#include "livox_gflags.h"
#include "publish.h"
#include "livox_parser.h"
#include "livox_lidar_def.h"
#include "livox_lidar_api.h"

namespace apollo {
namespace drivers {
namespace livox {

using apollo::cyber::Node;
using apollo::cyber::Writer;
using apollo::drivers::PointCloud;
using apollo::drivers::PointXYZIT;

class LivoxDriver : public apollo::drivers::lidar::LidarDriver {
 public:
  LivoxDriver(const std::shared_ptr<cyber::Node>& node,
                  const ::apollo::drivers::livox::Config& conf)
      : node_(node), conf_(conf) {}
  ~LivoxDriver() {
    stop();
    LivoxLidarSdkUninit();
    parse_thread_.join();
    publish_thread_.join();
  }

  bool Init() override;
  bool init();

  bool start() {
    return true;
  }

  bool stop() {
    stop_flag_ = true;
    return true;
  }

 private:
  bool InsertLivoxData(LidarPacket* data);
  bool InsertRawFrame(const std::shared_ptr<MixLidarFrame> frame);
  bool GetRawFrame(std::shared_ptr<MixLidarFrame>& frame);
  bool GetLidarPacket(LidarPacket* packet);

  static void OnLivoxLidarData(uint32_t handle, const uint8_t dev_type, LivoxLidarEthernetPacket* data, void* client_data);
  static void OnLivoxLidarInfoChange(const uint32_t handle, const LivoxLidarInfo* info, void* client_data);
  static void OnLivoxLidarWorkMode(livox_status status, uint32_t handle, LivoxLidarAsyncControlResponse* response, void* client_data);
  static uint64_t GetLivoxPacketTimestamp(const LivoxPacket* raw_packet);

  static void OnParseLidarData();
  static void LivoxDataProcess(const LidarPacket* packet, std::shared_ptr<MixLidarFrame>& current_frame_);

  static void OnPublishLidarData();

 public:
  static LivoxDriver* self;
  std::shared_ptr<cyber::Node> node_ = nullptr;
  Config conf_;
  bool stop_flag_ = false;
  std::map<uint32_t, std::string> devices_;
  LidarPacket livox_packet_buffer_;
  std::thread parse_thread_;
  std::thread publish_thread_;
  std::shared_ptr<CircularQueueBuffer<LidarPacket>> packet_buffer_;
  std::shared_ptr<CircularQueueBuffer<MixLidarFrame>> frame_buffer_;
  Publisher publisher_;
  LivoxParser livox_parser_;
};

}  // namespace livox
}  // namespace drivers
}  // namespace apollo

